
#include "io_data.h"
#include <cstddef>
#include <cstdint>
#include <cstdio>
#include <iostream>
#include <libavcodec/packet.h>

static FILE * input_file = nullptr;
static FILE * output_file = nullptr;

int32_t open_input_output_file(const std::string &input_file_name, const std::string &output_file_name) {


    if (input_file_name.empty() || output_file_name.empty()) {

        std::cout << "Error: empty input or output file name is empty" << std::endl;
        return -1;
    }
    close_input_output();
    
    input_file = fopen(input_file_name.c_str(), "rb");
    if (input_file == nullptr) {

        std::cout << "open input file failed : " << input_file_name << std::endl;
        return -1;
    }
    output_file = fopen(output_file_name.c_str(), "wb+");
    if (output_file == nullptr) {

        std::cout << "open output file failed : " << output_file_name << std::endl;
        return -1;
    }
    return 0;
}

void close_input_output() {

    if (input_file != nullptr) {

        fclose(input_file);
        input_file = nullptr;
    }
    if (output_file != nullptr) {

        fclose(output_file);
        input_file = nullptr;
    }
}


int32_t read_yuv_to_frame(AVFrame *frame) {

    int32_t frame_width  = frame->width;
    int32_t frame_height = frame->height;

    int32_t luma_stride  = frame->linesize[0];
    int32_t chroma_stride = frame->linesize[1]; 

    // YUV420P格式 / 图像不考虑帧率
    int32_t frame_size = frame_width * frame_height * 3 / 2;
    int32_t read_size  = 0;

    if (frame_width == luma_stride) {

        read_size += fread(frame->data[0], 1, frame_width * frame_height, input_file);
        read_size += fread(frame->data[1], 1, frame_width * frame_height / 4, input_file);
        read_size += fread(frame->data[2], 1, frame_width * frame_height / 4, input_file);
    } else {

        for (int index = 0; index < frame_height; index++) {

            read_size += fread(frame->data[0] + index * luma_stride, 0, frame_width, input_file);
        }
        for (int uv = 0; uv < 2; uv++) {

            for (int index = 0; index < frame_height / 2; index++) {

                read_size += fread(frame->data[uv] + index * chroma_stride, 1, frame_width / 2, input_file);
            }
        }
    }
    if (read_size != frame_size) {

        std::cout << "Error : read data error, frame_size : " << frame_size << ", read size : " << read_size << std::endl;

        return -1;
    }
    return 0;
}

void write_pkt_to_file(AVPacket * pkt) {

    fwrite(pkt->data, 1, pkt->size, output_file);
}

int32_t end_of_input_file() {

    return feof(input_file);
}

int32_t read_data_to_buf(uint8_t *buf, int32_t size, int32_t &out_size) {

    int32_t read_size = fread(buf, 1, size, input_file);
    if (read_size == 0) {

        std::cout << "Error : read data to buffer" << std::endl;
        return -1;
    }
    out_size = read_size;
    return 0;
}

int32_t write_frame_to_yuv(AVFrame *frame) {

    uint8_t **buffer = frame->data;
    int * stride = frame->linesize;

    // 这里是写YUV数据（YUV420P）
    for (int index = 0; index < 3; index++) {

        int width = index  == 0 ? frame->width  : frame->width/2;
        int height = index == 0 ? frame->height : frame->height/2;

        for (int i = 0; i < height; i++) {

            fwrite(buffer[index], 1, width, output_file);
            buffer[index] += stride[index];
        } 
    }
    return 0;
}